package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.rooms.absrooms.movechess.MoreColorCost;
import com.myk.game.gobangchess.rooms.absrooms.movechess.MovedChess;
import com.myk.game.gobangchess.rooms.absrooms.movechess.MovedChessRoom;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.GridsUtils;
import com.myk.game.gobangchess.utils.Pair;

import java.util.ArrayList;
import java.util.List;

/**
 * 双步象棋
 */
public class TwoStepXiangQiRoom extends Room implements MovedChessRoom {
    private final List<MovedChess> chessList = new ArrayList<>();
    private MovedChess selectedChess;
    private final List<int[]> moveArrayList = new ArrayList<>(2); // 走子标记
    private int curStep = 1; // 当前玩家步数用来轮换
    private MovedChess lastMovedChess;
    private List<Sign> chessboardStyle;
    private CacheSign cacheSign;

    public TwoStepXiangQiRoom(String roomName) {
        super(roomName, "中国象棋，但是可以一次走两步，意外的发现平衡性还挺好", "双步象棋", GridsUtils.createEmptyGrids(10, 9), true, true);
        cacheSign = new CacheSign(this, "background", 5, true, drawBackground()); //*** 修改背景样式记得改这里的版本号！！！
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return cacheSign;
    }

    @Override
    public String getGameInfo() {
        //先清空棋盘
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        signList.add(cacheSign);
        this.render();
        //画一下箭头
        for (int[] moveArray : moveArrayList) {
            signList.add(new LineSign(moveArray[0], moveArray[1], ColorCost.MOVE_ARROW_LIGHT, 1));
        }
        return super.getGameInfo();
    }

    @Override
    public String getCoordMode() {
        return "05040000";
    }

    private List<Sign> drawBackground() {
        chessboardStyle = new ArrayList<>();
        //背景
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(curGrids.length - 1, curGrids[0].length - 1), MoreColorCost.BOARD_BACKGROUND, MoreColorCost.BOARD_BACKGROUND, 1.8f, 0, 0));
        //边框
        addPath(0, 0, 0, 8, 2);
        addPath(9, 0, 9, 8, 2);
        addPath(0, 0, 9, 0, 2);
        addPath(0, 8, 9, 8, 2);
        //线条
        for (int i = 1; i < 9; i++) {
            addPath(i, 0, i, 8, 1);
        }
        for (int i = 1; i < 8; i++) {
            addPath(0, i, 4, i, 1);
            addPath(5, i, 9, i, 1);
        }
        //斜线条
        addXiePath(0, 3, 2, 5, 1);
        addXiePath(0, 5, 2, 3, 1);
        addXiePath(9, 3, 7, 5, 1);
        addXiePath(9, 5, 7, 3, 1);
        //青筋
        List<Integer> veinIndexes = new ArrayList<>();
        veinIndexes.add(getIndex(2, 1));
        veinIndexes.add(getIndex(2, 7));
        veinIndexes.add(getIndex(3, 2));
        veinIndexes.add(getIndex(3, 4));
        veinIndexes.add(getIndex(3, 6));
        veinIndexes.add(getIndex(7, 1));
        veinIndexes.add(getIndex(7, 7));
        veinIndexes.add(getIndex(6, 2));
        veinIndexes.add(getIndex(6, 4));
        veinIndexes.add(getIndex(6, 6));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(veinIndexes, MoreColorCost.BOARD_LINE).setCompAngle(0,0,0,0,1,1,1,1));
        List<Integer> vein2Indexes = new ArrayList<>();
        vein2Indexes.add(getIndex(3, 0));
        vein2Indexes.add(getIndex(6, 0));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(vein2Indexes, MoreColorCost.BOARD_LINE).setCompAngle(0,0,0,0,0,1,1,0));
        List<Integer> vein3Indexes = new ArrayList<>();
        vein3Indexes.add(getIndex(3, 8));
        vein3Indexes.add(getIndex(6, 8));
        chessboardStyle.add(FigureSign.makeBatchSingleFigure(vein3Indexes, MoreColorCost.BOARD_LINE).setCompAngle(0,0,0,0,1,0,0,1));

        //楚河汉界
        chessboardStyle.add(new TitleSign(0.25f, 0.5f, 0, "楚  河", MoreColorCost.BOARD_LINE, 0.5f));
        chessboardStyle.add(new TitleSign(0.75f, 0.5f, 0, "汉  界", MoreColorCost.BOARD_LINE, 0.5f));
        return chessboardStyle;
    }

    private void addXiePath(final int fRow, final int fCol, final int tRow, final int tCol, final float size) {
        List<Pair<Integer, Integer>> nodes = new ArrayList<>();
        nodes.add(new Pair<>(getIndex(fRow, fCol), 4));
        nodes.add(new Pair<>(getIndex(tRow, tCol), 4));
        chessboardStyle.add(new PathSign(nodes, MoreColorCost.BOARD_LINE, MoreColorCost.BOARD_LINE, size, 1));
    }

    private void addPath(final int fRow, final int fCol, final int tRow, final int tCol, final float size) {
        List<Pair<Integer, Integer>> nodes = new ArrayList<>();
        nodes.add(new Pair<>(getIndex(fRow, fCol), 4));
        nodes.add(new Pair<>(getIndex(tRow, tCol), 4));
        chessboardStyle.add(new PathSign(nodes, MoreColorCost.BOARD_LINE, MoreColorCost.BOARD_LINE, size, 0));
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        initChess();
        selectedChess = null;
        moveArrayList.clear();
        curStep = 1;
    }

    private void initChess() {
        chessList.clear();
        // 兵
        chessList.add(new Pawn(1, 3, 0));
        chessList.add(new Pawn(1, 3, 2));
        chessList.add(new Pawn(1, 3, 4));
        chessList.add(new Pawn(1, 3, 6));
        chessList.add(new Pawn(1, 3, 8));
        chessList.add(new Pawn(2, 6, 0));
        chessList.add(new Pawn(2, 6, 2));
        chessList.add(new Pawn(2, 6, 4));
        chessList.add(new Pawn(2, 6, 6));
        chessList.add(new Pawn(2, 6, 8));
        // 炮
        chessList.add(new Cannon(1, 2, 1));
        chessList.add(new Cannon(1, 2, 7));
        chessList.add(new Cannon(2, 7, 1));
        chessList.add(new Cannon(2, 7, 7));
        // 车
        chessList.add(new Chariot(1, 0, 0));
        chessList.add(new Chariot(1, 0, 8));
        chessList.add(new Chariot(2, 9, 0));
        chessList.add(new Chariot(2, 9, 8));
        // 马
        chessList.add(new Horse(1, 0, 1));
        chessList.add(new Horse(1, 0, 7));
        chessList.add(new Horse(2, 9, 1));
        chessList.add(new Horse(2, 9, 7));
        // 象
        chessList.add(new Bishop(1, 0, 2));
        chessList.add(new Bishop(1, 0, 6));
        chessList.add(new Bishop(2, 9, 2));
        chessList.add(new Bishop(2, 9, 6));
        // 士
        chessList.add(new Guard(1, 0, 3));
        chessList.add(new Guard(1, 0, 5));
        chessList.add(new Guard(2, 9, 3));
        chessList.add(new Guard(2, 9, 5));
        // 帅
        chessList.add(new General(1, 0, 4));
        chessList.add(new General(2, 9, 4));

    }

    @Override
    public String getRuleText() {
        return "在原来象棋的基础上；\n" +
                "-采用1222走子模式，但不能同一棋子动2次\n" +
                "-无法正常完成走完2步棋时，判负\n" +
                "-无必须应将的规则，吃掉对方将帅即获胜\n" +
                "-无将帅不照面规则，可以飞将吃对方将帅\n" +
                "-无循环规则";
    }

    private int getNextCur() {
        if (curStep == 0) {
            return cur;
        }
        else {
            return 3 - cur;
        }
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (selectOrMove(row, col)) {
            stepAdd();
            // 判断下一手是否无棋可走
            boolean canMove = false;
            // 判断是否吃了对方的帅
            int countGeneral = 0;
            for (MovedChess chess : chessList) {
                if (chess instanceof General) {
                    countGeneral++;
                }
                if (chess.getSide() == getNextCur() && chess != lastMovedChess && (!chess.getMoveRange(this).isEmpty() || !chess.getEatRange(this).isEmpty())) {
                    canMove = true;
                }
            }
            if (countGeneral < 2) {
                if (cur == 1) {
                    doOver(WinMode.BLACK_WIN, "黑方杀王白方");
                }
                else {
                    doOver(WinMode.WHITE_WIN, "白方杀王黑方");
                }
                return;
            }
            if (!canMove) {
                if (cur == 1) {
                    doOver(WinMode.BLACK_WIN, "黑方闷杀白方");
                }
                else {
                    doOver(WinMode.WHITE_WIN, "白方闷杀黑方");
                }
                return;
            }
            curStep++;
            if (cur == 1) {
                gameTip = "黑方还要走一步";
            }
            else {
                gameTip = "白方还要走一步";
            }
        }
        if (curStep == 2) {
            curStep = 0;
            lastMovedChess = null;
            if (cur == 1) {
                gameTip = "白方还要走二步";
                noticeWhiteMove();
            }
            else {
                gameTip = "黑方还要走二步";
                noticeBlackMove();
            }
        }
        else {
            noticeAllRefreshGameInfo();//通知界面刷新
        }
    }

    /**
     * 选择或走子
     *
     * @param row 点击位置的row
     * @param col 点击位置的col
     * @return 是否走子成功
     */
    private boolean selectOrMove(int row, int col) {
        MovedChess target = getChessByPos(row, col);
        if (target == null && selectedChess == null) {
            // 既没有点击棋子，又没有已选中的棋子
            return false;
        }
        if (selectedChess == null) {
            // 选中棋子
            if (target == lastMovedChess) {
                gameTip = "不能连续移动同一个棋子";
                return false;
            }
            selectedChess = target;
            return false;
        }
        if (selectedChess == target) {
            // 取消选中棋子
            selectedChess = null;
            noticeAllRefreshGameInfo();
            return false;
        }
        if (selectedChess.getSide() != cur) {
            // 选中的是对方的棋子，仅能查看，不能移动
            // 取消选中棋子
            selectedChess = null;
            noticeAllRefreshGameInfo();
            return false;
        }
        // 尝试走子
        int startIndex = getIndex(selectedChess.getRow(), selectedChess.getCol());
        int endIndex = getIndex(row, col);
        if (selectedChess.getMoveRange(this).contains(endIndex)) {
            selectedChess.moveTo(row, col);
            if (curStep == 0) {
                moveArrayList.clear();
            }
            moveArrayList.add(new int[]{startIndex, endIndex});
            lastMovedChess = selectedChess;
            selectedChess = null;
            return true;
        }
        else if (selectedChess.getEatRange(this).contains(endIndex)) {
            chessList.remove(getChessByPos(row, col));
            selectedChess.moveTo(row, col);
            if (curStep == 0) {
                moveArrayList.clear();
            }
            moveArrayList.add(new int[]{startIndex, endIndex});
            lastMovedChess = selectedChess;
            selectedChess = null;
            return true;
        }
        else {
            selectedChess = null;
            return false;
        }
    }

    @Override
    public List<MovedChess> getChessList() {
        return chessList;
    }

    @Override
    public MovedChess getSelectedChess() {
        return selectedChess;
    }

    @Override
    public int[][] getCurGrids() {
        return curGrids;
    }

    @Override
    public List<Sign> getSignList() {
        return signList;
    }

    @Override
    public MovedChess getChessByPos(int row, int col) {
        for (MovedChess chess : chessList) {
            if (chess.getRow() == row && chess.getCol() == col) {
                return chess;
            }
        }
        return null;
    }

    @Override
    public MovedChess getChessByIndex(int index) {
        for (MovedChess chess : chessList) {
            if (chess.getIndex(this) == index) {
                return chess;
            }
        }
        return null;
    }

    public static abstract class Chess implements MovedChess {
        public int row;
        public int col;
        private final int side;
        private final String name;

        public Chess(String name, int side, int row, int col) {
            this.name = name;
            this.side = side;
            this.row = row;
            this.col = col;
        }

        @Override
        public String getColor() {
            return getSide() == 1 ? MoreColorCost.RED_CHESS_WORD : MoreColorCost.WHITE_CHESS_WORD;
        }

        protected int getDirection() {
            if (getSide() == 1) {
                return 1;
            }
            else if (getSide() == 2) {
                return -1;
            }
            else {
                return 0;
            }
        }

        protected boolean inSelfBoard() {
            if (getSide() == 1) {
                return getRow() <= 4;
            }
            else {
                return getRow() >= 5;
            }
        }

        protected boolean inEnemyBoard() {
            if (getSide() == 1) {
                return getRow() >= 5;
            }
            else {
                return getRow() <= 4;
            }
        }

        @Override
        public int getRow() {
            return row;
        }

        @Override
        public int getCol() {
            return col;
        }

        @Override
        public void moveTo(int row, int col) {
            this.row = row;
            this.col = col;
        }

        @Override
        public int getSide() {
            return side;
        }

        @Override
        public String getName() {
            return name;
        }
    }

    private static class General extends Chess {
        public General(int mSide, int pRow, int pCol) {
            super("帅", mSide, pRow, pCol);
        }

        @Override
        public String getName() {
            return getSide() == 1 ? "帅" : "将";
        }

        @Override
        public List<Integer> getMoveRange(MovedChessRoom room) {
            List<Integer> range = genMoveRange(room, new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, 1);
            range.removeIf(i -> {
                int[] pos = room.getPositionByIndex(i);
                if (pos[1] < 3 || pos[1] > 5) {
                    return true;
                }
                return getSide() == 1 ? pos[0] > 2 : pos[0] < 7;
            });
            return range;
        }

        @Override
        public List<Integer> getEatRange(MovedChessRoom room) {
            List<Integer> range = genEatRange(room, new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, 1);
            range.removeIf(i -> {
                int[] pos = room.getPositionByIndex(i);
                if (pos[1] < 3 || pos[1] > 5) {
                    return true;
                }
                return getSide() == 1 ? pos[0] > 2 : pos[0] < 7;
            });
            // 白脸杀
            List<Integer> eatRange = genEatRange(room, new int[][]{{getDirection(), 0}}, Integer.MAX_VALUE);
            for (int index : eatRange) {
                if (room.getChessByIndex(index) instanceof General) {
                    range.add(index);
                }
            }
            return range;
        }
    }

    private static class Pawn extends Chess {
        public Pawn(int mSide, int pRow, int pCol) {
            super("兵", mSide, pRow, pCol);
        }

        @Override
        public String getName() {
            return getSide() == 1 ? "兵" : "卒";
        }

        @Override
        public List<Integer> getMoveRange(MovedChessRoom room) {
            if (inEnemyBoard()) {
                return genMoveRange(room, new int[][]{{getDirection(), 0}, {0, 1}, {0, -1}}, 1);
            }
            else {
                return genMoveRange(room, new int[][]{{getDirection(), 0}}, 1);
            }
        }

        @Override
        public List<Integer> getEatRange(MovedChessRoom room) {
            if (inEnemyBoard()) {
                return genEatRange(room, new int[][]{{getDirection(), 0}, {0, 1}, {0, -1}}, 1);
            }
            else {
                return genEatRange(room, new int[][]{{getDirection(), 0}}, 1);
            }
        }
    }

    private static class Chariot extends Chess {
        public Chariot(int mSide, int pRow, int pCol) {
            super("车", mSide, pRow, pCol);
        }

        @Override
        public String getName() {
            return getSide() == 1 ? "车" : "車";
        }

        @Override
        public List<Integer> getMoveRange(MovedChessRoom room) {
            return genMoveRange(room, new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE);
        }

        @Override
        public List<Integer> getEatRange(MovedChessRoom room) {
            return genEatRange(room, new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE);
        }
    }

    private static class Horse extends Chess {
        public Horse(int mSide, int pRow, int pCol) {
            super("马", mSide, pRow, pCol);
        }

        @Override
        public String getName() {
            return getSide() == 1 ? "马" : "馬";
        }

        @Override
        public List<Integer> getMoveRange(MovedChessRoom room) {
            List<Integer> range = new ArrayList<>();
            if (room.getChessByPos(getRow() + 1, getCol()) == null) {
                range.addAll(genMoveRange(room, new int[][]{{2, 1}, {2, -1}}, 1));
            }
            if (room.getChessByPos(getRow() - 1, getCol()) == null) {
                range.addAll(genMoveRange(room, new int[][]{{-2, 1}, {-2, -1}}, 1));
            }
            if (room.getChessByPos(getRow(), getCol() + 1) == null) {
                range.addAll(genMoveRange(room, new int[][]{{1, 2}, {-1, 2}}, 1));
            }
            if (room.getChessByPos(getRow(), getCol() - 1) == null) {
                range.addAll(genMoveRange(room, new int[][]{{1, -2}, {-1, -2}}, 1));
            }
            return range;
        }

        @Override
        public List<Integer> getEatRange(MovedChessRoom room) {
            List<Integer> range = new ArrayList<>();
            if (room.getChessByPos(getRow() + 1, getCol()) == null) {
                range.addAll(genEatRange(room, new int[][]{{2, 1}, {2, -1}}, 1));
            }
            if (room.getChessByPos(getRow() - 1, getCol()) == null) {
                range.addAll(genEatRange(room, new int[][]{{-2, 1}, {-2, -1}}, 1));
            }
            if (room.getChessByPos(getRow(), getCol() + 1) == null) {
                range.addAll(genEatRange(room, new int[][]{{1, 2}, {-1, 2}}, 1));
            }
            if (room.getChessByPos(getRow(), getCol() - 1) == null) {
                range.addAll(genEatRange(room, new int[][]{{1, -2}, {-1, -2}}, 1));
            }
            return range;
        }
    }

    private static class Cannon extends Chess {
        public Cannon(int mSide, int pRow, int pCol) {
            super("炮", mSide, pRow, pCol);
        }

        @Override
        public String getName() {
            return getSide() == 1 ? "炮" : "砲";
        }

        @Override
        public List<Integer> getMoveRange(MovedChessRoom room) {
            return genMoveRange(room, new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE);
        }

        @Override
        public List<Integer> getEatRange(MovedChessRoom room) {
            return genEatRange(room, new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE, 1, 1);
        }
    }

    private static class Bishop extends Chess {
        public Bishop(int mSide, int pRow, int pCol) {
            super("象", mSide, pRow, pCol);
        }

        @Override
        public String getName() {
            return getSide() == 1 ? "相" : "象";
        }

        @Override
        public List<Integer> getMoveRange(MovedChessRoom room) {
            List<Integer> range = genMoveRange(room, new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 2);
            range.removeAll(genMoveRange(room, new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 1));
            range.removeIf(i -> {
                int[] pos = room.getPositionByIndex(i);
                return getSide() == 1 ? pos[0] > 4 : pos[0] < 5;
            });
            return range;
        }

        @Override
        public List<Integer> getEatRange(MovedChessRoom room) {
            List<Integer> range = genEatRange(room, new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 2);
            range.removeAll(genEatRange(room, new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 1));
            range.removeIf(i -> {
                int[] pos = room.getPositionByIndex(i);
                return getSide() == 1 ? pos[0] > 4 : pos[0] < 5;
            });
            return range;
        }
    }

    private static class Guard extends Chess {
        public Guard(int mSide, int pRow, int pCol) {
            super("士", mSide, pRow, pCol);
        }

        @Override
        public String getName() {
            return getSide() == 1 ? "仕" : "士";
        }

        @Override
        public List<Integer> getMoveRange(MovedChessRoom room) {
            List<Integer> range = genMoveRange(room, new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 1);
            range.removeIf(i -> {
                int[] pos = room.getPositionByIndex(i);
                if (pos[1] < 3 || pos[1] > 5) {
                    return true;
                }
                return getSide() == 1 ? pos[0] > 2 : pos[0] < 7;
            });
            return range;
        }

        @Override
        public List<Integer> getEatRange(MovedChessRoom room) {
            List<Integer> range = genEatRange(room, new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 1);
            range.removeIf(i -> {
                int[] pos = room.getPositionByIndex(i);
                if (pos[1] < 3 || pos[1] > 5) {
                    return true;
                }
                return getSide() == 1 ? pos[0] > 2 : pos[0] < 7;
            });
            return range;
        }
    }
}
